グラフ探索 前編
2つのデータ管理方法
seen: その頂点を検知済みかどうかを表す配列
todo: 検知したがまだ訪問済みでない頂点の集合 (保留中の頂点の集合)
以下の擬似コードで表せる.
seen 全体を false に初期化して、todo を空にする
seen【s 】= true として、todo に s を追加する
todo が空になるまで以下を繰り返す:
todo → 32
todo から一つ頂点を取り出して v とする
T(v) の各要素 w に対して、
seen【w】= true であったならば、何もしない
そうでなかったら、seen【w】 = true として、todo に w を追加する
具体例
以下のような有向グラフを考えてみる
https://scrapbox.io/files/60f0b65fadd405001cb11b7d.png
code:swift
var graph: Int = Int.init(repeating: [], count: 1_000)
//graphを作成
graph0.append(1)
graph0.append(4)
graph0.append(2)
graph1.append(3)
graph1.append(8)
graph4.append(8)
graph2.append(5)
graph3.append(7)
graph8.append(3)
graph8.append(5)
graph5.append(6)
graph7.append(6)
//頂点を検知済みかどうかを表す配列
var seen = Bool.init(repeating: false, count: 100)
// 検知したがまだ訪問済みでない頂点の集合 (保留中の頂点の集合)
var todo = Int.init()
var record = Int.init()
//スタート0地点
seen0 = true
todo.append(0)
while !todo.isEmpty {
let Vs = graphtodo.first!
// 1
for i in Vs {
if !seeni {
seeni = true
todo.append(i)
}
}
record.append(todo.first!)
todo.removeFirst()
}
print(record)
//0, 1, 4, 2, 3, 8, 5, 7, 6
木構造について
木はグラフの一種
「サイクルを持たない」かつ「連結」(はぐれVがないこと)であるようなグラフのことを木という
https://scrapbox.io/files/60f0bed17c9039001c5c1cb0.webp
DFSは人間の思考に近い.
再帰関数と相性が良い
実装例
code:swift
//ここ重要 seenはグローバルに宣言するのもあり 今回は引数に渡している.
func dfs(graph: Int, v: Int, seen: inout Bool) {
//vに訪問済み
seenv = true
//graphv は 13,32,24のこと
for nextV in graphv {
//訪問済みならコンティニュー⛑
if seennextV { continue }
dfs(graph: graph, v: nextV, seen: &seen)
}
}
var graph = Int.init(repeating: [], count: 1000)
func main() {
//頂点の数,辺の数
let twoinput = readLine()!.split(separator: " ").map { Int($0)! }
let (V,E) = (twoinput0,twoinput1)
var seen = Bool.init(repeating: false, count: 1000)
//グラフを作成
_ = (0..<E).map { _ in
let (a,b) = readTwoInts()
grapha.append(b)
graphb.append(a)
}
//dfs
dfs(graph: graph, v: 1, seen: &seen)
print(graph)
}
main()
行きがけ順
根から初めて訪問した頂点の順序で順位をつけたもの」https://scrapbox.io/files/60f12ffbf33044001f3ba57e.webp
code:swift
func dfs(graph: Int, v: Int, seen: inout Bool, firstO: inout Int, count: inout Int) {
//vに訪問済み
seenv = true
count += 1
firstOv = count
for nextV in graphv {
//訪問済みならコンティニュー⛑
if seennextV { continue }
dfs(graph: graph, v: nextV, seen: &seen, firstO: &firstO, count: &count)
}
}
帰りがけ順
最後に訪問した頂点の順序で順位をつけたもの https://scrapbox.io/files/60f1301608ba60001c2fc7c2.webp
code:swift
func dfs(graph: Int, v: Int, seen: inout Bool, lastO: inout Int, count: inout Int) {
//vに訪問済み
seenv = true
for nextV in graphv {
//訪問済みならコンティニュー⛑
if seennextV { continue }
dfs(graph: graph, v: nextV, seen: &seen, lastO: &lastO, count: &count)
}
count += 1
lastOv = count
}
DFSの説明は以上次は実践篇
グラフ探索 DFS 後編